﻿using System;
using System.Windows;

namespace Microsoft.Popfly.GameCreator.GameEngine
{
    public static class MathUtils
    {
        // Point stuff
        public static Point Add(Point p1, Point p2)
        {
            return new Point(p1.X + p2.X, p1.Y + p2.Y);
        }

        public static Point Subtract(Point p1, Point p2)
        {
            return new Point(p1.X - p2.X, p1.Y - p2.Y);
        }

        public static double DotProduct(Point p1, Point p2)
        {
            return p1.X * p2.X + p1.Y * p2.Y;
        }

        public static double MagnitudeSquared(Point p)
        {
            return DotProduct(p, p);
        }

        public static double MagnitudeSquared(double x, double y)
        {
            return x * x + y * y;
        }

        public static double Magnitude(Point p)
        {
            return Math.Sqrt(MagnitudeSquared(p));
        }

        public static double Magnitude(double x, double y)
        {
            return Math.Sqrt(MagnitudeSquared(x, y));
        }

        public static double DistanceSquared(Point p1, Point p2)
        {
            return DistanceSquared(p1.X, p1.Y, p2.X, p2.Y);
        }

        public static double DistanceSquared(double x1, double y1, double x2, double y2)
        {
            return MagnitudeSquared(x1 - x2, y1 - y2);
        }

        public static double Distance(Point p1, Point p2)
        {
            return Math.Sqrt(DistanceSquared(p1, p2));
        }

        // Performs a linear interpolation between two vectors
        // The result is scale*100 percent away from p1 toward p2
        public static Point LinearInterpolate(Point p1, Point p2, double scale)
        {
            return Add(p1, Scale(Subtract(p2, p1), scale));
        }

        public static Point Normalize(Point p)
        {
            return Scale(p, 1.0 / Magnitude(p));
        }

        public static void Normalize(double x, double y, out double normalizedX, out double normalizedY)
        {
            double magnitude = Magnitude(x, y);
            normalizedX = x / magnitude;
            normalizedY = y / magnitude;
        }

        public static Point Scale(Point p, double scale)
        {
            return new Point(p.X * scale, p.Y * scale);
        }

        // rotation stuff
        public static double DegreesToRadians(double degrees)
        {
            return degrees * Math.PI / 180.0;
        }

        public static double RadiansToDegrees(double radians)
        {
            return radians * 180.0 / Math.PI;
        }

        public static void RotateRadians(double x, double y, double radians, out double xResult, out double yResult)
        {
            xResult = x * Math.Cos(radians) - y * Math.Sin(radians);
            yResult = x * Math.Sin(radians) + y * Math.Cos(radians);
        }

        public static Point RotateRadians(Point p, double radians)
        {
            return new Point(
                p.X * Math.Cos(radians) - p.Y * Math.Sin(radians),
                p.X * Math.Sin(radians) + p.Y * Math.Cos(radians));
        }

        public static Point Rotate(Point p, double degrees)
        {
            return RotateRadians(p, DegreesToRadians(degrees));
        }

        public static double AngleToPointRadians(Point p)
        {
            Point normalized = Normalize(p);

            double result = Math.Acos(normalized.X);

            // If we're on the bottom half of the circle, 
            // get the right angle
            if (normalized.Y < 0)
            {
                result = (2 * Math.PI) - result;
            }

            return result;
        }

        public static double AngleToPoint(Point p)
        {
            return RadiansToDegrees(AngleToPointRadians(p));
        }

        public static bool AreSameSign(double value1, double value2)
        {
            if ((value1 < 0 && value2 < 0) || (value1 >= 0 && value2 >= 0))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}
